package com.jean.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 
 * <一句话功能简述>AES加解密算法，使用Base64做转码以及辅助加密 <功能详细描述>
 * 
 * @author Jean
 * @version [版本号, 2013年12月3日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class EncryptTool
{
    /**
     * 加密密钥
     */
    private static final String SECRET_KEY = "JEAN_LOVE_JOANNE";
    
    /**
     * 向量IV
     */
    private static final String VECTOR_IV = "0102030405060708";
    
    /**
     * 日志对象
     */
    private static Logger logger = LoggerFactory.getLogger();
    
    /**
     * <一句话功能简述>加密 <功能详细描述>
     * 
     * @param plaintext 明文
     * @return 密文
     * @see [类、类#方法、类#成员]
     */
    public static String encrypt(String plaintext)
    {
        String ciphertext = "";
        if (StringUtils.isBlank(plaintext))
        {
            logger.warn("The plaintext is blank.");
            return ciphertext;
        }
        ciphertext = encrypt(plaintext, SECRET_KEY);
        return ciphertext;
    }
    
    /**
     * <一句话功能简述>解密 <功能详细描述>
     * 
     * @param ciphertext 密文
     * @return 明文
     * @see [类、类#方法、类#成员]
     */
    public static String decrypt(String ciphertext)
    {
        String plaintext = "";
        if (StringUtils.isBlank(ciphertext))
        {
            logger.warn("The plaintext is blank.");
            return plaintext;
        }
        plaintext = decrypt(ciphertext, SECRET_KEY);
        return plaintext;
    }
    
    /**
     * <一句话功能简述>加密 <功能详细描述>
     * 
     * @param plaintext 明文
     * @param secretKey 密钥
     * @return 密文
     * @see [类、类#方法、类#成员]
     */
    private static String encrypt(String plaintext, String secretKey)
    {
        byte[] raw = secretKey.getBytes();
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = null;
        try
        {
            // "算法/模式/补码方式"
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        }
        catch (NoSuchAlgorithmException | NoSuchPaddingException e)
        {
            logger.error("Encryption abnormal: ", e);
        }
        // 使用CBC模式，需要一个向量iv，可增加加密算法的强度
        IvParameterSpec iv = new IvParameterSpec(VECTOR_IV.getBytes());
        try
        {
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
        }
        catch (InvalidKeyException | InvalidAlgorithmParameterException e)
        {
            logger.error("Encryption abnormal: ", e);
        }
        byte[] encrypted = null;
        try
        {
            encrypted = cipher.doFinal(plaintext.getBytes());
        }
        catch (IllegalBlockSizeException | BadPaddingException e)
        {
            logger.error("Encryption abnormal: ", e);
        }
        // 使用BASE64做转码功能，同时能起到2次加密的作用
        return new BASE64Encoder().encode(encrypted);
    }
    
    /**
     * <一句话功能简述>解密 <功能详细描述>
     * 
     * @param ciphertext 密文
     * @param secretKey 密钥
     * @return 明文
     * @see [类、类#方法、类#成员]
     */
    private static String decrypt(String ciphertext, String secretKey)
    {
        byte[] raw = null;
        try
        {
            raw = secretKey.getBytes("ASCII");
        }
        catch (UnsupportedEncodingException e)
        {
            logger.error("Decryption abnormal: ", e);
        }
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = null;
        try
        {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        }
        catch (NoSuchAlgorithmException | NoSuchPaddingException e)
        {
            logger.error("Decryption abnormal: ", e);
        }
        IvParameterSpec iv = new IvParameterSpec(VECTOR_IV.getBytes());
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        }
        catch (InvalidKeyException | InvalidAlgorithmParameterException e)
        {
            logger.error("Decryption abnormal: ", e);
        }
        byte[] encrypted = null;
        try
        {
            // 先用base64解密
            encrypted = new BASE64Decoder().decodeBuffer(ciphertext);
        }
        catch (IOException e)
        {
            logger.error("Decryption abnormal: ", e);
        }
        byte[] original = null;
        try
        {
            original = cipher.doFinal(encrypted);
        }
        catch (IllegalBlockSizeException | BadPaddingException e)
        {
            logger.error("Decryption abnormal: ", e);
        }
        return new String(original);
    }
}
